////////////////////////////////////////////////////////////////////////////////
/// @file    play_wavfile.c
/// @author  AE TEAM
/// @brief   THIS FILE PROVIDES ALL THE SYSTEM FUNCTIONS.
////////////////////////////////////////////////////////////////////////////////
/// @attention
///
/// THE EXISTING FIRMWARE IS ONLY FOR REFERENCE, WHICH IS DESIGNED TO PROVIDE
/// CUSTOMERS WITH CODING INFORMATION ABOUT THEIR PRODUCTS SO THEY CAN SAVE
/// TIME. THEREFORE, MINDMOTION SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT OR
/// CONSEQUENTIAL DAMAGES ABOUT ANY CLAIMS ARISING OUT OF THE CONTENT OF SUCH
/// HARDWARE AND/OR THE USE OF THE CODING INFORMATION CONTAINED HEREIN IN
/// CONNECTION WITH PRODUCTS MADE BY CUSTOMERS.
///
/// <H2><CENTER>&COPY; COPYRIGHT MINDMOTION </CENTER></H2>
////////////////////////////////////////////////////////////////////////////////
// Define to prevent recursive inclusion
#define _PLAY_WAVFILE_C_


#include "HAL_conf.h"
#include "HAL_device.h"
#include <stdio.h>
#include <string.h>

#include "uart.h"
#include "delay.h"

#include "ff.h"
#include "fatfs.h"
#include "sdio.h"

#include "sdio_sdcard.h"
#include "i2s_config.h"
#include "play_tone.h"
#include "wav_operate.h"
#include "play_wavfile.h"

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup MM32_Example_Layer
/// @{

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup PLAY_WAVFILE
/// @{

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup PLAY_WAVFILE_Exported_Constants
/// @{

//#define READBUF_SIZE 4096
//#define BUFF_SIZE 2304

//int bytesLeft;

//u8  readBuf[READBUF_SIZE];
//u8* readPtr;
//int offset;
//static  short buffer3[BUFF_SIZE] = {0x00};
//static  short buffer4[BUFF_SIZE] = {0x00};
//short*   Decbuf;

//SPI_I2S_AUDIO_FREQ_TypeDef  samprate;

//static uint8_t buffer_switch = 1;
//static FIL fsrc;      // file objects

//UINT BytesRead;



#define FULLBUFFERBYTELEN  (512*8)
#define HALFBUFFERLEN  (FULLBUFFERBYTELEN/2)
#define FULLBUUFERHALFWORDLEN  (FULLBUFFERBYTELEN/2)
#define HALFBUUFERHALFWORDLEN  (FULLBUFFERBYTELEN/4)


//u16 I2sSendBuffer[1024];// 512 halfword , 1024 bytes;
u8  FileReadBuffer[FULLBUFFERBYTELEN];
u32 RealReadbackBytesNumber;

bool FileEndFlag = 0;

////////////////////////////////////////////////////////////////////////////////
/// @brief  Transfer files.
/// @param  None.
/// @retval  0.
////////////////////////////////////////////////////////////////////////////////
static void I2S_TX_DMA_Init(u16* buf0, u16 num)
{

    DMA_InitTypeDef  DMA_InitStructure;
    RCC_AHBPeriphClockCmd(RCC_AHBENR_DMA2, ENABLE);
    DMA_DeInit(DMA2_Channel2);

    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32) & (SPI3->TXREG);
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)buf0;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = num;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_InitStructure.DMA_Auto_reload = DMA_Auto_Reload_Enable;
    DMA_Init(DMA2_Channel2, &DMA_InitStructure);
}
void WaveDataDmaLoad(uint32_t Addr, uint32_t Size)
{
    DMA_Channel_TypeDef* ch;
    ch = DMA2_Channel2;
    CLEAR_BIT(SPI3->GCR, SPI_GCR_SPIEN);
    MODIFY_REG(ch->CCR, DMA_CCR_EN, DISABLE << DMA_CCR_EN_Pos);
    ch->CMAR = Addr;
    ch->CNDTR = Size;
    SET_BIT(SPI3->GCR, SPI_GCR_SPIEN);
    MODIFY_REG(ch->CCR, DMA_CCR_EN, ENABLE << DMA_CCR_EN_Pos);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Transfer files.
/// @param  None.
/// @retval  0.
////////////////////////////////////////////////////////////////////////////////
void PlayWaveFile(void)
{
    u32 waittoSendCounter = 0;
    readwavfile();
    while(1) {
        f_lseek(&fileR, WaveCounter);
        FileEndFlag = 0;
        if(WaveLen > FULLBUFFERBYTELEN) {
            f_read(&fileR, FileReadBuffer, FULLBUFFERBYTELEN, &RealReadbackBytesNumber);
            waittoSendCounter = WaveLen - FULLBUFFERBYTELEN;
            FileEndFlag = 0;
            I2S_TX_DMA_Init((u16*)&FileReadBuffer[0], FULLBUFFERBYTELEN / 2);
            DMA_Cmd(DMA2_Channel2, ENABLE);
        }
        else {
            f_read(&fileR, FileReadBuffer, WaveLen, &RealReadbackBytesNumber);
            FileEndFlag = 1;
            I2S_TX_DMA_Init((u16*)&FileReadBuffer[0], RealReadbackBytesNumber / 2);
            DMA_Cmd(DMA2_Channel2, ENABLE);
        }

        while(1) {
            if(FileEndFlag == 0) {
                if(DMA_GetITStatus(DMA2_IT_HT2) == SET) {
                    DMA_ClearITPendingBit(DMA2_IT_HT2);

                    if(waittoSendCounter > HALFBUFFERLEN) {
                        f_read(&fileR, FileReadBuffer, HALFBUFFERLEN, &RealReadbackBytesNumber);
                        waittoSendCounter = waittoSendCounter - HALFBUFFERLEN;
                        FileEndFlag = 0;
                    }
                    else {
                        f_read(&fileR, FileReadBuffer, waittoSendCounter, &RealReadbackBytesNumber);
                        if((HALFBUFFERLEN - waittoSendCounter) != 0) {
                            memset(FileReadBuffer + waittoSendCounter, 0, HALFBUFFERLEN + HALFBUFFERLEN - waittoSendCounter);
                        }
                        waittoSendCounter = 0;
                        FileEndFlag = 1;
                    }
                }
                else if(DMA_GetITStatus(DMA2_IT_TC2) == SET) {
                    DMA_ClearITPendingBit(DMA2_IT_TC2);

                    if(waittoSendCounter > HALFBUFFERLEN) {
                        f_read(&fileR, FileReadBuffer + HALFBUFFERLEN, HALFBUFFERLEN, &RealReadbackBytesNumber);
                        waittoSendCounter = waittoSendCounter - HALFBUFFERLEN;
                        FileEndFlag = 0;
                    }
                    else {
                        f_read(&fileR, FileReadBuffer + HALFBUFFERLEN, waittoSendCounter, &RealReadbackBytesNumber);
                        if((HALFBUFFERLEN - waittoSendCounter) != 0) {
                            memset(FileReadBuffer + HALFBUFFERLEN + waittoSendCounter, 0, HALFBUFFERLEN - waittoSendCounter);
                        }
                        waittoSendCounter = 0;
                        FileEndFlag = 1;
                    }
                }
            }
            else {
                if(DMA_GetITStatus(DMA2_IT_TC2) == SET) {
                    DMA_ClearITPendingBit(DMA2_IT_GL2);
                    DMA_ClearITPendingBit(DMA2_IT_TC2);
                    f_lseek(&fileR, WaveCounter);
                    waittoSendCounter = 0;
                    FileEndFlag = 0;
                    RealReadbackBytesNumber = 0;
                    f_lseek(&fileR, WaveCounter);
                    break;
                }

            }
        }

    }
}
/*
void PlayWaveFile(void)
{
    DIR dirs;
    FILINFO finfo;
    FRESULT res;
    static UINT br;

    DELAY_Init();
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOC | RCC_AHBPeriph_GPIOD | RCC_AHBPeriph_GPIOE, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBENR_SDIO, ENABLE);
    CONSOLE_Init(115200);

    SDIO_ConfigInit();
    printf("SDCARD TEST\r\n");
    while(SD_Init()) {
        printf("SD Card Error!\r\n");
    }
    MX_FATFS_Init();
    f_mount(&SDFatFS, (TCHAR const*)SDPath, 0);

    do {
        res = f_open(&fsrc, "0:/song.wav", FA_READ);
    } while(FR_OK != res);
//    WaveLen = 0;
//    f_read(&fsrc, buffer1, 512, &BytesRead);
//    while(1) {
//        if(WaveParsing(buffer1) == 0) {
//            break;
//        }
//    }
//    WaveLen = WAVE_Format.DataSize;



    u16 buff[2] = {0x01, 0x02};
    I2S_TX_DMA_Init(&buff[0], 1);
    DMA_Cmd(DMA2_Channel2, ENABLE);

//  while(1){
    if (f_opendir(&dirs, "") == FR_OK) {              //success to open directory
        while (f_readdir(&dirs, &finfo) == FR_OK) {       //if there is file in this directory
            if (finfo.fattrib & AM_ARC) {
                if(!finfo.fname[0])
                    break;
                printf("\r\n Now Playing:[");
                printf(finfo.fname);
                printf("]\r\n");
                res = f_open(&fsrc, finfo.fname, FA_OPEN_EXISTING | FA_READ);
                SET_BIT(SPI3->GCR, SPI_GCR_SPIEN);
                MODIFY_REG(DMA2_Channel2->CCR, DMA_CCR_EN, ENABLE << DMA_CCR_EN_Pos);

                hMP3Decoder = MP3InitDecoder();

                readPtr = readBuf;
                res = f_read(&fsrc, readBuf, READBUF_SIZE, &br);
                bytesLeft += br;

                buffer_switch = 0;
                while(1) {
                    offset = MP3FindSyncWord(readPtr, bytesLeft); //assume EOF if no sync found
                    if(offset < 0)break;
                    readPtr += offset; //data start point
                    bytesLeft -= offset; //in buffer
                    if(bytesLeft < READBUF_SIZE) {
                        memmove(readBuf, readPtr, bytesLeft);
                        res = f_read(&fsrc, readBuf + bytesLeft, READBUF_SIZE - bytesLeft, &br);
                        if((res) || (br == 0)) break;
                        if(br < READBUF_SIZE - bytesLeft)
                            memset(readBuf + bytesLeft + br, 0, READBUF_SIZE - bytesLeft - br);
                        bytesLeft = READBUF_SIZE;
                        readPtr = readBuf;
                    }

                    while(1) {
                        if(DMA_GetITStatus(DMA2_IT_TC2) == SET) {
                            DMA_ClearITPendingBit(DMA2_IT_TC2);

                            if(buffer_switch == 0) {
                                WaveDataDmaLoad((u32)buffer4, BUFF_SIZE);
                                //MP3Decode(hMP3Decoder, &readPtr, &bytesLeft, buffer3, 0);
                                buffer_switch = 1;
                                break;
                            }
                            else {
                                WaveDataDmaLoad((u32)buffer3, BUFF_SIZE);
                                //MP3Decode(hMP3Decoder, &readPtr, &bytesLeft, buffer4, 0);
                                buffer_switch = 0;
                                break;
                            }
                        }
                    }

                }
                CLEAR_BIT(SPI3->GCR, SPI_GCR_SPIEN);
                MODIFY_REG(DMA2_Channel2->CCR, DMA_CCR_EN, DISABLE << DMA_CCR_EN_Pos);
                f_close(&fsrc);
                bytesLeft = 0;
            }
        }
    }
    while(1);
//   }


}
*/

////////////////////////////////////////////////////////////////////////////////
/// @brief  play music.
/// @param  None.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void PlayWaveFileDmaPollingDemo(void)
{
    //  initI2S_CodecMode1();
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOC | RCC_AHBPeriph_GPIOD | RCC_AHBPeriph_GPIOE, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBENR_SDIO, ENABLE);

    I2S_CODEC_Init();

    StartPlay();
    I2S_PWR_ON();

    while(1) {
        PlayWaveFile();
    }
}

/// @}

/// @}

/// @}

